package com.nulldev.util.internal.backport.arrays;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;

import com.nulldev.util.JVM.Arguments;
import com.nulldev.util.JVM.JVM;
import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.concurrency.threadIt.v4.emapi.ExecutorManager;
import com.nulldev.util.concurrency.threadIt.v4.emapi.uft.Executable;
import com.nulldev.util.data.Arrays.arrays.ConcurrentList;
import com.nulldev.util.internal.backport.concurrency9.Lists;

public class BackportList {

	/*
	 * TODO: This file still assumed that v3 would have pre-JRE 8 support, we didn't
	 * do that. Remove the old sort() emulating code once all deadlocks are nuked
	 * out of existence.
	 */

	/**
	 * Disabled by default as of 3.0-alpha-80. <br>
	 * Reason: Sometimes isn't invoked correctly, leading to a deadlock.
	 */
	private static final boolean ENABLE_TASKED_SORTING = Arguments.hasArgument("--Backport.enableTaskedSorting");
	private static final boolean USE_NEW_SORT_LOGIC = Arguments.notArguments("--BackportList.useOldSortLogic");
	private static final boolean USE_NATIVE_SORT = Arguments.hasArgument("--Backport.useNativeSort");

	/**
	 * Backported Function: List&lt;E&gt;.sort()
	 * 
	 * @param <T>
	 * @param list - The list object.
	 * @param c    the {@code Comparator} used to compare list elements. A
	 *             {@code null} value indicates that the elements'
	 *             {@linkplain Comparable natural ordering} should be used
	 * @throws ClassCastException            if the list contains elements that are
	 *                                       not <i>mutually comparable</i> using
	 *                                       the specified comparator
	 * @throws UnsupportedOperationException if the list's list-iterator does not
	 *                                       support the {@code set} operation
	 * @throws IllegalArgumentException      (<a href=
	 *                                       "Collection.html#optional-restrictions">optional</a>)
	 *                                       if the comparator is found to violate
	 *                                       the {@link Comparator} contract
	 * @not-backport 1.8
	 */
	@SuppressWarnings(
		{ "unchecked", "rawtypes" })
	public static <T> void sort(final List<T> list, final Comparator<? super T> c) {
		if (list.size() <= 1) {
			return;
		} else if (USE_NATIVE_SORT && JVM.version() >= 1.8f) {
			if (list instanceof ConcurrentList)
				((ConcurrentList<T>) list).navSort(c);
			else
				list.sort(c);
		} else if (ENABLE_TASKED_SORTING) {
			// FIXME: Causes moderate deadlocks.
			ExecutorManager.globalAsyncSubmit(() -> {
				final Object[] a = list.toArray();
				BackportArrays.parallelSort(a, (Comparator) c);
				if (USE_NEW_SORT_LOGIC) {
					list.clear();
					list.addAll((Collection<? extends T>) Lists.of(a));
				} else {
					final ListIterator<T> i = list.listIterator();
					for (final Object e : a) {
						i.next();
						i.set((T) e);
					}
				}
				return null;
			}).waitTillCompletion();
		} else {
			if (list instanceof ConcurrentList) {
				((ConcurrentList<T>) list).navSort(c);
			} else {
				final Object[] a = list.toArray();
				BackportArrays.sort(a, (Comparator) c);
				if (USE_NEW_SORT_LOGIC) {
					list.clear();
					list.addAll((Collection<? extends T>) Lists.of(a));
				} else {
					final ListIterator<T> i = list.listIterator();
					for (final Object e : a) {
						i.next();
						i.set((T) e);
					}
				}
			}
		}
	}

	@SuppressWarnings(
		{ "unchecked", "rawtypes" })
	public static <T> Executable<Object> sortLater(final List<T> list, final Comparator<? super T> c) {
		// FIXME: Causes moderate deadlocks.
		return ExecutorManager.globalAsyncSubmit(() -> {
			if (USE_NATIVE_SORT && JVM.version() >= 1.8f) {
				list.sort(c);
			} else {
				final Object[] a = list.toArray();
				BackportArrays.parallelSort(a, (Comparator) c);
				if (USE_NEW_SORT_LOGIC) {
					list.clear();
					list.addAll((Collection<? extends T>) Lists.of(a));
				} else {
					final ListIterator<T> i = list.listIterator();
					for (final Object e : a) {
						i.next();
						i.set((T) e);
					}
				}
			}
			return null;
		});
	}

	public static void main(String[] args) {
		final List<Integer> o = new ArrayList<Integer>(5);
		o.add(6);
		o.add(1);
		o.add(2);
		o.add(9);
		o.add(3);
		final long s = System.currentTimeMillis();
		sort(o, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				return o1.compareTo(o2);
			}
		});
		final long e = System.currentTimeMillis();
		JVM.println("invkTime: " + (e - s));
		ArrayUtils.printLln(o);
	}
}
